﻿/*! Copyright (c) 2010 Brandon Aaron (http://brandonaaron.net)
 * Dual licensed under the MIT (MIT_LICENSE.txt)
 * and GPL Version 2 (GPL_LICENSE.txt) licenses.
 *
 * Version: 1.1.1
 * Requires jQuery 1.3+
 * Docs: http://docs.jquery.com/Plugins/livequery
 */


(function (factory) {
    if (typeof define === "function" && define.amd) {
        define(["jquery"], factory);
    } else {
        factory(jQuery);
    }
}(function ($) {

    $.extend($.fn, {
        livequery: function (type, fn, fn2) {

            //code by FuzhePan - 统一处理livequery多次绑定的问题。
            this.expire(type, fn, fn2);

            var self = this, q;

            // Handle different call patterns
            if ($.isFunction(type)) {
                fn2 = fn, fn = type, type = undefined;
            }
                //code by FuzhePan - 给出提示：不要使用livequery进行事件绑定。
            else {
                //兼容IE8的判断
                if (typeof console != "undefined") {
                    console.warn("event bind please use jQuery,not livequery!");
                }
            }

            // See if Live Query already exists
            $.each($.livequery.queries, function (i, query) {
                if (self.selector == query.selector && self.context == query.context &&
                    type == query.type && (!fn || fn.$lqguid == query.fn.$lqguid) && (!fn2 || fn2.$lqguid == query.fn2.$lqguid))
                    // Found the query, exit the each loop
                    return (q = query) && false;
            });

            // Create new Live Query if it wasn't found
            q = q || new $.livequery(this.selector, this.context, type, fn, fn2);

            // Make sure it is running
            q.stopped = false;

            // Run it immediately for the first time
            q.run();

            // Contnue the chain
            return this;
        },

        expire: function (type, fn, fn2) {
            var self = this;

            // Handle different call patterns
            if ($.isFunction(type))
                fn2 = fn, fn = type, type = undefined;

            // Find the Live Query based on arguments and stop it
            $.each($.livequery.queries, function (i, query) {
                if (self.selector == query.selector && self.context == query.context &&
                    (!type || type == query.type) && (!fn || fn.$lqguid == query.fn.$lqguid) && (!fn2 || fn2.$lqguid == query.fn2.$lqguid) && !this.stopped)
                    $.livequery.stop(query.id);
            });

            // Continue the chain
            return this;
        }
    });

    $.livequery = function (selector, context, type, fn, fn2) {
        this.selector = selector;
        this.context = context;
        this.type = type;
        this.fn = fn;
        this.fn2 = fn2;
        this.elements = [];
        this.stopped = false;

        // The id is the index of the Live Query in $.livequery.queries
        this.id = $.livequery.queries.push(this) - 1;

        // Mark the functions for matching later on
        fn.$lqguid = fn.$lqguid || $.livequery.guid++;
        if (fn2) fn2.$lqguid = fn2.$lqguid || $.livequery.guid++;

        // Return the Live Query
        return this;
    };

    $.livequery.prototype = {
        stop: function () {
            var query = this;

            if (this.type)
                // Unbind all bound events
                this.elements.unbind(this.type, this.fn);
            else if (this.fn2)
                // Call the second function for all matched elements
                this.elements.each(function (i, el) {
                    query.fn2.apply(el);
                });

            // Clear out matched elements
            this.elements = [];

            // Stop the Live Query from running until restarted
            this.stopped = true;
        },

        run: function () {
            // Short-circuit if stopped
            if (this.stopped) return;
            var query = this;

            var oEls = this.elements,
                els = $(this.selector, this.context),
                nEls = els.not(oEls);

            // Set elements to the latest set of matched elements
            this.elements = els;

            if (this.type) {

                // Bind events to newly matched elements
                nEls.bind(this.type, this.fn);

                // Unbind events to elements no longer matched
                if (oEls.length > 0)
                    $.each(oEls, function (i, el) {
                        if ($.inArray(el, els) < 0)
                            $.event.remove(el, query.type, query.fn);
                    });
            }
            else {
                // Call the first function for newly matched elements
                nEls.each(function () {
                    query.fn.apply(this);
                });

                //commenet by FuzhePan : 因为伙伴中用不到fn2,注释掉这段代码以提高效率
                //// Call the second function for elements no longer matched
                //if ( this.fn2 && oEls.length > 0 )
                //	$.each(oEls, function(i, el) {
                //		if ( $.inArray(el, els) < 0 )
                //			query.fn2.apply(el);
                //	});
            }
        }
    };

    $.extend($.livequery, {
        guid: 0,
        queries: [],
        queue: [],
        running: false,
        timeout: null,

        checkQueue: function () {
            if ($.livequery.running && $.livequery.queue.length) {
                var length = $.livequery.queue.length;
                // Run each Live Query currently in the queue
                while (length--)
                    $.livequery.queries[$.livequery.queue.shift()].run();
            }
        },

        pause: function () {
            // Don't run anymore Live Queries until restarted
            $.livequery.running = false;
        },

        play: function () {
            // Restart Live Queries
            $.livequery.running = true;
            // Request a run of the Live Queries
            $.livequery.run();
        },

        registerPlugin: function () {
            $.each(arguments, function (i, n) {
                // Short-circuit if the method doesn't exist
                if (!$.fn[n]) return;

                // Save a reference to the original method
                var old = $.fn[n];

                // Create a new method
                $.fn[n] = function () {
                    // Call the original method
                    var r = old.apply(this, arguments);

                    // Request a run of the Live Queries
                    $.livequery.run();

                    // Return the original methods result
                    return r;
                }
            });
        },

        run: function (id) {
            if (id != undefined) {
                // Put the particular Live Query in the queue if it doesn't already exist
                if ($.inArray(id, $.livequery.queue) < 0)
                    $.livequery.queue.push(id);
            }
            else
                // Put each Live Query in the queue if it doesn't already exist
                $.each($.livequery.queries, function (id) {
                    if ($.inArray(id, $.livequery.queue) < 0)
                        $.livequery.queue.push(id);
                });

            // Clear timeout if it already exists
            if ($.livequery.timeout) clearTimeout($.livequery.timeout);
            // Create a timeout to check the queue and actually run the Live Queries
            $.livequery.timeout = setTimeout($.livequery.checkQueue, 20);
        },

        stop: function (id) {
            if (id != undefined)
                // Stop are particular Live Query
                $.livequery.queries[id].stop();
            else
                // Stop all Live Queries
                $.each($.livequery.queries, function (id) {
                    $.livequery.queries[id].stop();
                });
        }
    });

    // Register core DOM manipulation methods
    $.livequery.registerPlugin('append', 'prepend', 'after', 'before', 'wrap', 'replaceWith', 'html');

    // Run Live Queries when the Document is ready
    $(function () { $.livequery.play(); });

}));